from scapy.all import *
from scapy.layers.l2 import ARP, Ether
from scapy.layers.inet6 import IPv6
from scapy.layers.inet import IP, ICMP, TCP, in4_chksum, UDP

def send_mac(dst_mac,payload,count):
    result_text = ""
    # 验证MAC地址格式
    if not dst_mac:
        result_text += "请输入目的MAC地址!\n"
        return result_text

    # 循环发送指定次数的数据帧
    for i in range(count):
        # 使用scapy构造以太网帧: Ether(dst=目标MAC) / Raw(负载数据)
        ether_frame = Ether(dst=dst_mac) / Raw(load=payload)
        # 发送数据帧，verbose=0表示不显示详细发送信息
        sendp(ether_frame, verbose=0)
        result_text += f"发送数据帧 {i + 1}/{count}，目的MAC: {dst_mac}\n"
    return result_text

def send_arp(dst_mac,dst_ip,payload,count,network_type,protocol_type,op_type):
    result_text = ""
    if not dst_ip:
        result_text += "请输入目的IP地址!\n"
        return result_text
    # 确定操作码 (1=请求, 2=应答)
    op_code = 1 if op_type == "请求" else 2

    # 循环发送指定次数的ARP包
    for i in range(count):
        # 使用scapy构造ARP包
        arp_packet = ARP(
            hwtype=1,  # 硬件类型 (以太网=1)
            ptype=0x0800,  # 协议类型 (IPv4=0x0800)
            hwlen=6,  # 硬件地址长度 (MAC地址=6字节)
            plen=4,  # 协议地址长度 (IPv4=4字节)
            op=op_code,  # 操作码 (1=请求, 2=应答)
            hwdst=dst_mac,  # 目标硬件地址
            pdst=dst_ip  # 目标协议地址
        )

        # 构造以太网帧包装ARP包
        # 如果目标MAC是广播地址或空，则使用广播MAC
        eth_dst = dst_mac if dst_mac and dst_mac != "FF:FF:FF:FF:FF:FF" else "ff:ff:ff:ff:ff:ff"
        ether_frame = Ether(dst=eth_dst) / arp_packet

        # 如果有负载数据，则添加到包中
        if payload:
            ether_frame = ether_frame / Raw(load=payload)
        # 发送以太网帧，verbose=0表示不显示详细发送信息
        sendp(ether_frame, verbose=0)
        result_text += f"发送ARP包 {i+1}/{count}，目的IP: {dst_ip}，操作码: {op_type}\n"
    return result_text

# 发送IP数据包
def send_ip(dst_ip,src_ip,payload,count,ip_version):
    result_text = ""

    # 验证必要参数
    if not dst_ip:
        result_text += "请输入目的IP地址!\n"
        return

    # 循环发送指定次数的IP包
    for i in range(count):
        # 使用scapy构造IP包
        # 根据选择的IP版本构造不同的IP包
        if ip_version == "IPV6":
            # 对于IPv6，使用IPv6类
            ip_packet = IPv6(
                src=src_ip if src_ip else None,  # 源IP地址
                dst=dst_ip,  # 目的IP地址
            )
        else:
            # 对于IPv4，使用IP类
            ip_packet = IP(
                src=src_ip if src_ip else None,  # 源IP地址
                dst=dst_ip  # 目的IP地址
            )

        # 如果有负载数据，则添加到包中
        if payload:
            ip_packet = ip_packet / Raw(load=payload)

        # 发送IP包，verbose=0表示不显示详细发送信息
        send(ip_packet, verbose=0)

        # 在结果文本框中显示发送详情
    result_text += f"发送IP包 {count}个，目的IP: {dst_ip}，IP版本: {ip_version}\n"

# 发送TCP数据包
def send_tcp(dst_ip,src_ip,payload,count,ip_version,dst_port,src_port,window_size,seq_num,ack_num,urg_flag,ack_flag,psh_flag,rst_flag,syn_flag,fin_flag):
    result_text = ""
    # 验证必要参数
    if not dst_ip:
        result_text += "请输入目的IP地址!\n"
        return
    if not dst_port:
        result_text += "请输入目的端口!\n"
        return

    # 循环发送指定次数的TCP包
    for i in range(count):
        # 构造TCP包
        tcp_packet = TCP(
            sport=int(src_port) if src_port else 12345,  # 源端口
            dport=int(dst_port),  # 目的端口
            seq=int(seq_num) if seq_num else 0,  # 序列号
            ack=int(ack_num) if ack_num else 0,  # 确认号
            window=int(window_size) if window_size else 8192,  # 窗口大小
            flags=(urg_flag << 5) | (ack_flag << 4) | (psh_flag << 3) |
                  (rst_flag << 2) | (syn_flag << 1) | fin_flag  # 控制位
        )

        # 根据IP版本构造IP包并封装TCP包
        if ip_version == "IPV6":
            # 对于IPv6，使用IPv6类
            ip_packet = IPv6(
                src=src_ip if src_ip else None,  # 源IP地址
                dst=dst_ip  # 目的IP地址
            )
            # 组合IPv6包和TCP包
            full_packet = ip_packet / tcp_packet
        else:
            # 对于IPv4，使用IP类
            ip_packet = IP(
                src=src_ip if src_ip else None,  # 源IP地址
                dst=dst_ip  # 目的IP地址
            )
            # 组合IP包和TCP包
            full_packet = ip_packet / tcp_packet

        # 如果有负载数据，则添加到包中
        if payload:
            full_packet = full_packet / Raw(load=payload)

        # 发送TCP包，verbose=0表示不显示详细发送信息
        send(full_packet, verbose=0)
    result_text += f"发送TCP包 {count}个，目的IP: {dst_ip}，目的端口: {dst_port}\n"

# 发送UDP数据包
def send_udp(dst_ip,src_ip,payload,count,ip_version,dst_port,src_port):
    result_text = ""

    # 验证必要参数
    if not dst_ip:
        result_text += "请输入目的IP地址!\n"
        return

    if not dst_port:
        result_text += "请输入目的端口!\n"
        return
    # 循环发送指定次数的UDP包
    for i in range(count):
        # 构造UDP包
        udp_packet = UDP(
            sport=int(src_port) if src_port else 12345,  # 源端口
            dport=int(dst_port)  # 目的端口
        )

        # 根据IP版本构造IP包并封装UDP包
        if ip_version == "IPV6":
            # 对于IPv6，使用IPv6类
            ip_packet = IPv6(
                src=src_ip if src_ip else None,  # 源IP地址
                dst=dst_ip  # 目的IP地址
            )
            # 组合IPv6包和UDP包
            full_packet = ip_packet / udp_packet
        else:
            # 对于IPv4，使用IP类
            ip_packet = IP(
                src=src_ip if src_ip else None,  # 源IP地址
                dst=dst_ip  # 目的IP地址
            )
            # 组合IP包和UDP包
            full_packet = ip_packet / udp_packet

        # 如果有负载数据，则添加到包中
        if payload:
            full_packet = full_packet / Raw(load=payload)

        # 发送UDP包，verbose=0表示不显示详细发送信息
        send(full_packet, verbose=0)
    result_text += f"发送UDP包 {count}个，目的IP: {dst_ip}，目的端口: {dst_port}\n"
